﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SlimDX;

namespace System.Windows.Media.Media3D10
{
    /// <summary>
    /// Spécifie une transformation de rotation. 
    /// </summary>
    public sealed class RotateTransform3D10 : AffineTransform3D10
    {
        #region Dependency Properties
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="CenterX"/>.
        /// </summary>
        public static readonly DependencyProperty CenterXProperty =
            DependencyProperty.Register("CenterX", typeof(float), typeof(RotateTransform3D10),
            new PropertyMetadata(0.0f, new PropertyChangedCallback(CenterX_PropertyChanged)));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="CenterY"/>.
        /// </summary>
        public static readonly DependencyProperty CenterYProperty =
            DependencyProperty.Register("CenterY", typeof(float), typeof(RotateTransform3D10),
            new PropertyMetadata(0.0f, new PropertyChangedCallback(CenterY_PropertyChanged)));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="CenterZ"/>.
        /// </summary>
        public static readonly DependencyProperty CenterZProperty =
            DependencyProperty.Register("CenterZ", typeof(float), typeof(RotateTransform3D10),
            new PropertyMetadata(0.0f, new PropertyChangedCallback(CenterZ_PropertyChanged)));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="Rotation"/>.
        /// </summary>
        public static readonly DependencyProperty RotationProperty =
            DependencyProperty.Register("Rotation", typeof(Rotation3D10), typeof(RotateTransform3D10),
            new PropertyMetadata(new PropertyChangedCallback(Rotation_PropertyChanged)));
        #endregion

        #region DependencyProperties Callbacks
        private static void CenterX_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ((RotateTransform3D10)sender).OnCenterXChanged(e);
        }

        private static void CenterY_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ((RotateTransform3D10)sender).OnCenterYChanged(e);
        }

        private static void CenterZ_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ((RotateTransform3D10)sender).OnCenterZChanged(e);
        }

        private static void Rotation_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ((RotateTransform3D10)sender).OnRotationChanged(e);
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="RotateTransform3D10"/>
        /// </summary>
        public RotateTransform3D10()
            : base()
        {
            this.Rotation = Rotation3D10.Identity;
        }

        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="RotateTransform3D10"/> avec la rotation spécifiée. 
        /// </summary>
        /// <param name="rotation"><see cref="Rotation3D10"/> qui spécifie la rotation.</param>
        public RotateTransform3D10(Rotation3D10 rotation)
            : base()
        {
            this.Rotation = rotation;
        }

        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="RotateTransform3D10"/> avec la rotation et le centre spécifiés. 
        /// </summary>
        /// <param name="rotation"><see cref="Rotation3D10"/> qui spécifie la rotation.</param>
        /// <param name="center">Centre de la rotation de la transformation.</param>
        public RotateTransform3D10(Rotation3D10 rotation, SlimDX.Vector3 center)
            : this(rotation, center.X, center.Y, center.Z)
        { }

        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="RotateTransform3D10"/> avec la rotation et les coordonnées du centre spécifiées.
        /// </summary>
        /// <param name="rotation"><see cref="Rotation3D10"/> qui spécifie la rotation.</param>
        /// <param name="centerX">Double qui spécifie la valeur X de référence pour la rotation.</param>
        /// <param name="centerY">Double qui spécifie la valeur Y de référence pour la rotation.</param>
        /// <param name="centerZ">Double qui spécifie la valeur Z de référence pour la rotation.</param>
        public RotateTransform3D10(Rotation3D10 rotation, float centerX, float centerY, float centerZ)
            : base()
        {
            this.Rotation = rotation;
            this.CenterX = centerX;
            this.CenterY = centerY;
            this.CenterZ = centerZ;
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Obtient ou définit la coordonnée X du <see cref="SlimDX.Vector3"/> autour duquel pivoter. 
        /// </summary>
        public float CenterX
        {
            get { return (float)GetValue(CenterXProperty); }
            set { SetValue(CenterXProperty, value); }
        }

        /// <summary>
        /// Obtient ou définit la coordonnée Y du <see cref="SlimDX.Vector3"/> autour duquel pivoter. 
        /// </summary>
        public float CenterY
        {
            get { return (float)GetValue(CenterYProperty); }
            set { SetValue(CenterYProperty, value); }
        }

        /// <summary>
        /// Obtient ou définit la coordonnée Z du <see cref="SlimDX.Vector3"/> autour duquel pivoter. 
        /// </summary>
        public float CenterZ
        {
            get { return (float)GetValue(CenterZProperty); }
            set { SetValue(CenterZProperty, value); }
        }

        /// <summary>
        /// Obtient ou définit un <see cref="Rotation3D10"/> qui spécifie la rotation. 
        /// </summary>
        public Rotation3D10 Rotation
        {
            get { return (Rotation3D10)GetValue(RotationProperty); }
            set { SetValue(RotationProperty, value); }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Crée un clone modifiable de ce <see cref="RotateTransform3D10"/>, en créant des copies complètes des valeurs de cet objet.
        /// Lors de la copie de propriétés de dépendance, cette méthode copie les références de ressources et les liaisons de données (même si elles ne peuvent plus être résolues), mais pas les animations ni leurs valeurs actuelles.
        /// </summary>
        /// <returns>
        /// Clone modifiable de l'objet actuel.
        /// La valeur de la propriété <see cref="Freezable.IsFrozen"/> de l'objet cloné est false, même si la valeur de la propriété <see cref="Freezable.IsFrozen"/> de la source est true.
        /// </returns>
        public new RotateTransform3D10 Clone()
        {
            return base.Clone() as RotateTransform3D10;
        }

        /// <summary>
        /// Crée un clone modifiable de ce <see cref="RotateTransform3D10"/>, en créant des copies complètes des valeurs actuelles de cet objet.
        /// Contrairement à leurs valeurs actuelles, les références de ressources, les liaisons de données et les animations ne sont pas copiées.
        /// </summary>
        /// <returns>
        /// Clone modifiable de l'objet actuel.
        /// La valeur de la propriété <see cref="Freezable.IsFrozen"/> de l'objet cloné est false, même si la valeur de la propriété <see cref="Freezable.IsFrozen"/> de la source est true.
        /// </returns>
        public new RotateTransform3D10 CloneCurrentValue()
        {
            return base.CloneCurrentValue() as RotateTransform3D10;
        }
        #endregion

        #region Private Methods
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822")]
        private void OnCenterXChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822")]
        private void OnCenterYChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822")]
        private void OnCenterZChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822")]
        private void OnRotationChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
        }
        #endregion

        #region Transform3D10 Implementation
        /// <summary>
        /// Récupère un <see cref="SlimDX.Matrix"/> qui représente la rotation.
        /// </summary>
        public override SlimDX.Matrix Value
        {
            get { return this.Rotation.Value; }
        }
        #endregion

        #region Freezable Implementation
        /// <summary>
        /// Une fois implémentée dans une classe dérivée, initialise une nouvelle instance de la classe dérivée <see cref="Freezable"/>. 
        /// </summary>
        /// <returns>Nouvelle instance.</returns>
        protected override Freezable CreateInstanceCore()
        {
            return new RotateTransform3D10();
        }
        #endregion
    }
}
